package com.gotrade.ftpdemo.service.impl;

import com.gotrade.ftpdemo.common.FTPClientProperties;
import com.gotrade.ftpdemo.model.FileInfo;
import com.gotrade.ftpdemo.pool.FTPClientFactory;
import com.gotrade.ftpdemo.service.FileSystemService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.io.*;
import java.util.Arrays;

/**
 * @author jason.tang
 * @create 2019-03-07 13:33
 * @description
 */
@Slf4j
@Service("fileSystemService")
public class FileSystemServiceImpl implements FileSystemService {

    @Autowired
    private FTPClientFactory ftpClientFactory;

    @Autowired
    private FTPClientProperties config;

    private GenericObjectPool<FTPClient> ftpClientPool;

    @PostConstruct
    public void autoStartup() {
        ftpClientPool = new GenericObjectPool<>(ftpClientFactory);
    }

    @Override
    public boolean uploadFile(FileInfo fileInfo) {
        FTPClient ftpClient = null;
        BufferedInputStream inStream = null;
        try {
            ftpClient = ftpClientPool.borrowObject();

            // 验证FTP服务器是否登录成功
            int replyCode = ftpClient.getReplyCode();
            if (!FTPReply.isPositiveCompletion(replyCode)) {
                log.error("ftpServer refused connection, replyCode:{}", replyCode);
                return false;
            }

            // 更改FTP会话的当前工作目录
            ftpClient.changeWorkingDirectory(config.getBaseUrl());
            if (!fileInfo.getRemoteDir().isEmpty()) {
                String[] dirs = fileInfo.getRemoteDir().split("/");
                String[] resDir = Arrays.stream(dirs)
                        .filter(StringUtils::isNotBlank)
                        .toArray(String[]::new);
                for (String dir : resDir) {
                    if (!ftpClient.changeWorkingDirectory(dir)) {
                        if (!ftpClient.makeDirectory(dir)) {
                            log.error("Create directory failure, directory:{}", dir);
                            return false;
                        }
                        ftpClient.changeWorkingDirectory(dir);
                        log.info("Change working directory: {}", dir);
                    }
                }
            }

            inStream = new BufferedInputStream(new FileInputStream(fileInfo.getLocalFile()));
            final int retryTimes = 2;

            for (int j = 0; j <= retryTimes; j++) {
                boolean success = ftpClient.storeFile(fileInfo.getFileName(), inStream);
                if (success) {
                    log.info("Upload file success! {}", fileInfo.getRemoteDir() + "/" + fileInfo.getFileName());
                    return true;
                }
                log.warn("Upload file failure! try uploading again... {} times", j);
            }
        } catch (FileNotFoundException e) {
            log.error("File not found!{}", fileInfo.getLocalFile());
        } catch (Exception e) {
            log.error("Upload file failure!", e);
        } finally {
            IOUtils.closeQuietly(inStream);
            //将对象放回池中
            ftpClientPool.returnObject(ftpClient);
        }
        return false;
    }

    @Override
    public boolean downloadFile(FileInfo fileInfo) {
        FTPClient ftpClient = null;
        OutputStream outputStream = null;
        try {
            ftpClient = ftpClientPool.borrowObject();
            // 验证FTP服务器是否登录成功
            int replyCode = ftpClient.getReplyCode();
            if (!FTPReply.isPositiveCompletion(replyCode)) {
                log.error("FtpServer refused connection, replyCode:{}", replyCode);
                return false;
            }
            String workingDir = config.getBaseUrl() + fileInfo.getRemoteDir();
            if(!ftpClient.changeWorkingDirectory(workingDir)) {
                log.error("Remote directory cannot open!", workingDir);
                return false;
            }
            FTPFile[] ftpFiles = ftpClient.listFiles();
            for (FTPFile file : ftpFiles) {
                if (fileInfo.getFileName().equalsIgnoreCase(file.getName())) {
                    outputStream = new FileOutputStream(fileInfo.getLocalFile());
                    ftpClient.retrieveFile(file.getName(), outputStream);
                    log.info("Download file : {}", fileInfo.getRemoteDir() + "/" + fileInfo.getFileName());
                }
            }
            ftpClient.logout();
            return true;
        } catch (Exception e) {
            log.error("Download file failure!", e);
        } finally {
            IOUtils.closeQuietly(outputStream);
            ftpClientPool.returnObject(ftpClient);
        }
        return false;
    }
}